
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/smp.h>

/*
linux/smp.h

Call a function on all processors
void on_each_cpu(smp_call_func_t func, void *info, int wait);

Call a function on processors specified by mask, which might include
the local one.
void on_each_cpu_mask(const struct cpumask *mask, smp_call_func_t func,
		void *info, bool wait);

Call a function on all other processors
void smp_call_function(smp_call_func_t func, void *info, int wait);

void smp_call_function_many(const struct cpumask *mask,
			    smp_call_func_t func, void *info, bool wait);

int smp_call_function_any(const struct cpumask *mask,
			  smp_call_func_t func, void *info, int wait);

int smp_call_function_single(int cpuid, smp_call_func_t func, void *info,
			     int wait);

 *     cpu_possible_mask- has bit 'cpu' set iff cpu is populatable
 *     cpu_present_mask - has bit 'cpu' set iff cpu is populated
 *     cpu_online_mask  - has bit 'cpu' set iff cpu available to scheduler
 *     cpu_active_mask  - has bit 'cpu' set iff cpu available to migration
              
*/

static void smp_print_id(void *t)
{
    unsigned int cur_cpu = smp_processor_id();
    printk("cur cpuid: %d, %d\n", cur_cpu, get_cpu());
}

static int __init smp_test_init(void)
{
    cpumask_t cpu_mask;
    int cpu_id = get_cpu();
    int res = 0;

    // 每一个core都执行
    on_each_cpu(smp_print_id, NULL, 1);
    printk("finish on each cpu\n");

    // cpu_online_mask 当前在线的core掩码
    on_each_cpu_mask(cpu_online_mask, smp_print_id, NULL, 1);
    printk("finish on each cpu cpu_online_mask [0x%lx]\n", cpu_online_mask->bits[0]);

    // 根据指定的掩码在对应的core上执行
    cpu_mask.bits[0] = 0xf;
    on_each_cpu_mask(&cpu_mask, smp_print_id, NULL, 1);
    printk("finish on each cpu mask [0x%lx]\n", cpu_mask.bits[0]);

    // 除了当前core，其他core都要执行
    smp_call_function(smp_print_id, NULL, 1);
    printk("smp_call_function finish cur_cpu %d\n", cpu_id);

    // 在给定的掩码对应的core上执行，除了当前core
    cpu_mask.bits[0] |= 1 << cpu_id;
    smp_call_function_many(&cpu_mask, smp_print_id, NULL, 1);
    printk("smp_call_function_many cpu mask cur_cpu %d [0x%lx]\n", cpu_id, cpu_mask.bits[0]);

    // 给定cpumask对应core中选择一个core执行一次
    // cpu_mask.bits[0] = 1 << cpu_id; // 测试是否会在当前核中执行
    res = smp_call_function_any(&cpu_mask, smp_print_id, NULL, 1);
    printk("smp_call_function_any cur_cpu %d res [%d] mask[0x%lx]\n", cpu_id, res, cpu_mask.bits[0]);

    // 指定core执行一次
    res = smp_call_function_single(cpu_id, smp_print_id, NULL, 1);
    printk("smp_call_function_single cur_cpu %d res [%d] mask[0x%lx]\n", cpu_id, res, cpu_mask.bits[0]);

    return 0;
}

static void __exit smp_test_exit(void)
{
    printk(KERN_DEBUG "byebye\n");
}

module_init(smp_test_init);
module_exit(smp_test_exit);

MODULE_AUTHOR("ystlong@163.com>");
MODULE_DESCRIPTION("Linux Kernel sysfs kobj test");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.1");
